In this post I'm trying to explain how I've developed the PW.JSON library for .NET. This Library can convert Objects to JSON strings and viceversa with the standard defined on www.json.org.
I've searched on links in www.json.org site but I've not found some axample in VB.NET. There is a VB 6 version, a C# very complete and complex version but nothing else, so searching on the web I've found this sample at http://mikeoncode.blogspot.com/2007/05/json-re-visited-from.html.
Then I've modified the code of Mike Griffiths for managing double quoted strings instead of single quoted (the JSON standard is double quoted) and I've managed null properties aof the objects (properties set to Nothing).
The new code is this:
Imports System.Text
Friend Class NetJSON
#Region " Private Declarations"
Dim myName As String = ""
Dim myContent As New Hashtable
Const dblQuote As Char = Chr(34)
#End Region
#Region " Enumerations"
Private Enum dataType
dt_Nothing
dt_Boolean
dt_Decimal
dt_Double
dt_Integer
dt_string
dt_Array
dt_NetJSON
End Enum
#End Region
#Region " Public Constructors, Methods and Properties"
Public Sub New()
End Sub
Public Sub New(ByVal nameString As String)
myName = nameString
End Sub
Public Sub AddNameValue(ByVal nameString As String, ByVal Value As Object)
StoreValue(nameString, Value)
End Sub
Public Overrides Function toString() As String
Dim Resp As New StringBuilder
Dim Firstcall As Boolean = True
Dim TailBrace As String = "}"
If myName.Length > 0 Then
Resp.Append("{" & dblQuote & myName & dblQuote & ": {")
TailBrace &= "}"
Else
Resp.Append("{")
End If
Dim myEnumerator As IDictionaryEnumerator = myContent.GetEnumerator()
While myEnumerator.MoveNext
Resp.Append(IIf(Firstcall, "", ", ") & dblQuote & myEnumerator.Key & dblQuote & ": " & MakeString(myEnumerator.Value))
Firstcall = False
End While
Resp.Append(TailBrace)
Return Resp.ToString()
End Function
#End Region
#Region " Private Functions and Subroutines"
Private Function MakeString(ByVal ThisData As Object) As String
Dim ThisType As dataType = GetDataType(ThisData)
If ThisType = dataType.dt_Array Then
Dim TestArray(ThisData.length) As Object
Dim aLoop As Int16
Dim ArrayStruct As New StringBuilder("[")
Dim FirstCall As Boolean = True
ThisType = GetDataType(ThisData(0))
For aLoop = 0 To ThisData.Length - 1
ArrayStruct.Append(IIf(FirstCall, "", ", ") & MakeElementString(ThisData(aLoop), ThisType))
FirstCall = False
Next
ArrayStruct.Append("]")
Return ArrayStruct.ToString()
Else
Return MakeElementString(ThisData, ThisType)
End If
End Function
Private Function MakeElementString(ByVal ThisData As Object, ByVal ThisDataType As dataType)
Select Case ThisDataType
Case dataType.dt_Boolean
Return IIf(CBool(ThisData), "true", "false")
Case dataType.dt_Decimal
Return String.Format("{0}", ThisData).Replace(","c, "."c)
Case dataType.dt_string
Return Chr(34) & CType(ThisData, String).Replace("\", "\\").Replace("/", "\/").Replace(vbCrLf, "\n").Replace(vbTab, "\t").Replace(Chr(34), "\" & Chr(34)) & Chr(34)
Case dataType.dt_Nothing
Return "null"
Case dataType.dt_NetJSON
Return ThisData.ToString()
Case Else
Return ""
End Select
End Function
Private Function GetDataType(ByVal Value As Object) As dataType
If TypeOf Value Is Array Then
Return dataType.dt_Array
ElseIf TypeOf Value Is Single Or TypeOf Value Is Double Then
Return dataType.dt_Double
ElseIf TypeOf Value Is Decimal Then
Return dataType.dt_Decimal
ElseIf TypeOf Value Is Boolean Then
Return dataType.dt_Boolean
ElseIf TypeOf Value Is String Then
Return dataType.dt_string
ElseIf TypeOf Value Is Integer Or TypeOf Value Is Int16 Or TypeOf Value Is Int32 Or TypeOf Value Is Int64 Then
Return dataType.dt_Integer
ElseIf TypeOf Value Is NetJSON Then
Return dataType.dt_NetJSON
ElseIf Value Is Nothing Then
Return dataType.dt_Nothing
End If
End Function
Private Sub StoreValue(ByVal nameString As String, ByVal Value As Object)
Select Case GetDataType(Value)
Case dataType.dt_Array
Dim copyArray(Value.length - 1) As Object
For aLoop As Int16 = 0 To Value.length - 1
copyArray(aLoop) = Value(aLoop)
Next
myContent.Add(nameString, copyArray)
Case dataType.dt_Boolean
Dim wrkBoolean As Boolean = CBool(Value)
myContent.Add(nameString, wrkBoolean)
Case dataType.dt_Double, dataType.dt_Integer, dataType.dt_Decimal
Dim wrkDecimal As Decimal = CDec(Value)
myContent.Add(nameString, wrkDecimal)
Case dataType.dt_string
Dim wrkString As String = CStr(Value)
myContent.Add(nameString, wrkString)
Case dataType.dt_NetJSON
myContent.Add(nameString, Value)
Case dataType.dt_Nothing
myContent.Add(nameString, Nothing)
End Select
End Sub
#End Region
End Class
The NetJSON class help us on creating JSON strings but we must think in terms of name/value properties. I'll convert any type of object in JSON strings, so I've developed The JSONHelper class below:
Imports System.Reflection
Public Class JSONHelper
#Region "Gestione Object via Reflection"
Public Shared Function ObjectToString(ByVal Obj As Object) As String
If Obj Is Nothing Then Return ""
Dim _t As Type = Obj.GetType()
Return ConvertSubObjectToNetJSON("", Obj).toString
End Function
Private Shared Function ConvertSubObjectToNetJSON(ByVal Name As String, ByRef Obj As Object) As NetJSON
If Obj Is Nothing Then Return Nothing
Dim _t As Type = Obj.GetType()
Dim result As New NetJSON(Name)
For Each _p As PropertyInfo In _t.GetProperties()
If _p.PropertyType.IsPrimitive Then
result.AddNameValue(_p.Name, _p.GetValue(Obj, Nothing))
ElseIf _p.PropertyType.IsArray Then
result.AddNameValue(_p.Name, _p.GetValue(Obj, Nothing))
ElseIf _p.PropertyType.IsClass AndAlso _p.PropertyType.Name <> GetType(String).Name Then
result.AddNameValue(_p.Name, ConvertSubObjectToNetJSON("", _p.GetValue(Obj, Nothing)))
ElseIf _p.PropertyType.Name = GetType(String).Name Then
result.AddNameValue(_p.Name, _p.GetValue(Obj, Nothing))
Else
ThrowNew NotImplementedException("Property Type '" & _p.PropertyType.Name & "' not yet implemented")
End If
Next
Return result
End Function
Public Shared Function StringToObject(ByVal JSONString As String, ByVal ClassType As Type) As Object
Dim ojson As New JSON.JSONObject
Return ojson.parse(JSONString, ClassType)
End Function
#End Region
End Class
Using the PropertyInfo calss of System.Reflection namespace I convert each object peoprerty in a Name/Value property of NetJSON class.
Note that if a property is of Date type, the code will raise a NotImplementedException. This is correct because the JSON standard don't define date data type.
This is how to use ObjectToString method:
Imports PW.JSON
Module Module1
Class Prova
Private _id As Integer
Private _name As String
Private _valido As Boolean
Private _subObject As Prova
Private _numero As Integer
Private _numeroDec As Double
Private _array() As String
Public Property ID() As Integer
Get
Return _id
End Get
Set(ByVal value As Integer)
_id = value
End Set
End Property
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Public Property Valido() As Boolean
Get
Return _valido
End Get
Set(ByVal value As Boolean)
_valido = value
End Set
End Property
Public Property SubObject() As Prova
Get
Return _subObject
End Get
Set(ByVal value As Prova)
_subObject = value
End Set
End Property
Public Property NumeroDec() As Double
Get
Return _numeroDec
End Get
Set(ByVal value As Double)
_numeroDec = value
End Set
End Property
Public Property Array() As String()
Get
Return _array
End Get
Set(ByVal value As String())
_array = value
End Set
End Property
Public Sub New(ByVal ID As Integer, ByVal Name As String)
_id = ID
_name = Name
End Sub
Public Function SomeMethod() As String
Return "Method: " & _id
End Function
End Class
Sub Main()
Dim objprova As New Prova(1, "Nome Object")
objprova.Array = Split("A E I O U")
objprova.NumeroDec = 100.34
objprova.SubObject = New Prova(2, "Nome - SubObject")
objprova.Valido = True
Console.WriteLine(PW.JSON.JSONHelper.ObjectToString(objprova))
Console.ReadLine()
End Sub
End Module
The resulting JSON string is:
{"NumeroDec": 100.34, "Name": "Nome Object", "Array": ["A", "E", "I", "O", "U"], "SubObject": {"NumeroDec": 0, "Name": "Nome - SubObject", "Array": null, "SubObject": null, "Valido": false, "ID": 2}, "Valido": true, "ID": 1}
Now we can see the StringToObject method that convert JSON string in Object. We can use the output of the previous example:
Sub Main()
Dim strJSON As String = "{""NumeroDec"": 100.34, ""Name"": ""Nome Object"", " & _
" ""Array"": [""A"", ""E"", ""I"", ""O"", ""U""], " & _
" ""SubObject"": {""NumeroDec"": 0, ""Name"": ""Nome - SubObject"", " & _
" ""Array"": null, ""SubObject"": null, ""Valido"": false, ""ID"": 2}, " & _
" ""Valido"": true, ""ID"": 1}"
Dim objprova As Prova
objprova = PW.JSON.JSONHelper.StringToObject(strJSON, GetType(Prova))
Console.WriteLine(objprova.Name)
Console.WriteLine(objprova.SubObject.Name)
Console.ReadLine()
End Sub
The result is:
Nome Object
Nome - SubObject
If you want to see all the source code, or download the PW.JSON library (PW.JSON.dll) and you are a registered user, click here.